/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.ext.echarts.builder.impl;

import cn.easyplatform.web.ext.ComponentHandler;
import cn.easyplatform.web.ext.echarts.ECharts;
import cn.easyplatform.web.ext.echarts.lib.Option;
import com.google.gson.JsonArray;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class RadarChartsBuilder extends AbstractChartsBuilder {

    private final String updateSign = "1.0.0";
    private static final boolean DEBUG = false;

    private static final List<Object[]> mData = new ArrayList<>();

    static {
        mData.add(new Object[]{"小李", "思想觉悟", 90, 100});
        mData.add(new Object[]{"小李", "工作态度", 95, 100});
        mData.add(new Object[]{"小李", "办事效率", 93, 120});
        mData.add(new Object[]{"小李", "颜值身材", 50, 100});
        mData.add(new Object[]{"小李", "谈吐风度", 60, 100});
        mData.add(new Object[]{"小刘", "思想觉悟", 90, 100});
        mData.add(new Object[]{"小刘", "工作态度", 91, 100});
        mData.add(new Object[]{"小刘", "办事效率", 89, 120});
        mData.add(new Object[]{"小刘", "颜值身材", 70, 100});
        mData.add(new Object[]{"小刘", "谈吐风度", 65, 100});
        mData.add(new Object[]{"小叶", "思想觉悟", 88, 100});
        mData.add(new Object[]{"小叶", "工作态度", 87, 100});
        mData.add(new Object[]{"小叶", "办事效率", 90, 120});
        mData.add(new Object[]{"小叶", "颜值身材", 60, 100});
        mData.add(new Object[]{"小叶", "谈吐风度", 60, 100});
    }

    public RadarChartsBuilder(String type) {
        super(type);
    }

    @Override
    protected void setSeries(Option option, String name, JsonArray data) {
        super.setSeries(option, name, data);
    }

    /**
     * 构建雷达图
     *
     * @param charts      雷达图模板
     * @param dataHandler 数据消息
     */
    @Override
    public void build(ECharts charts, ComponentHandler dataHandler) {
        if (DEBUG) {
            if (dataHandler == null) {
                createModel(charts, mData);
            }
            return;
        }
        if (dataHandler == null) {
            build(charts.getOption(), getTemplate(charts.getTemplate()), true);
        } else if (charts.getQuery() != null) {
            List<Object[]> data = dataHandler.selectList0(Object[].class, charts.getDbId(), (String) charts.getQuery());
            createModel(charts, data);
        } else {
            // Series是Map形式
            if (charts.getOption().getSeries() instanceof Map) {
                Map<String, Object> radar = (Map<String, Object>) charts.getOption().getSeries();
                if (radar.get("query") != null) {
                    List<Object[]> data = dataHandler.selectList0(Object[].class, charts.getDbId(),
                            radar.get("query").toString());
                    createModel(charts, data);
                }
            }
            // Series是List形式
            else if (charts.getOption().getSeries() instanceof List) {
                List<?> series = (List<?>) charts.getOption().getSeries();
                if (series.size() == 1) { // 单个Series
                    Map<String, Object> radar = (Map<String, Object>) series.get(0);
                    if (radar.get("query") != null) {
                        List<Object[]> data = dataHandler.selectList0(Object[].class, charts.getDbId(),
                                radar.get("query").toString());
                        createModel(charts, data);
                    }
                } else { // 多个Series

                }
            }
        }
    }

    /**
     * 声明：
     * 数据库查询格式要求：bigType, type, value, (maxValue),
     * 描述： bigType：雷达图所描述的对象  type：该对象的各项指标  value：每项指标的实际值  maxValue(可选)：每项指标的参考值（最大值）
     * 举例： 员工姓名， 员工指标（工作效率、工作态度等），指标分数（90分）, 指标标准（100分）
     *
     * @param charts 雷达图模板
     * @param model  数据库返回数据
     */
    private void createModel(ECharts charts, List<Object[]> model) {
        // 无数据
        if (model.isEmpty()) {
            List<Object[]> newModel = new ArrayList<>();
            newModel.add(new Object[]{"暂无数据", "暂无数据", 0});
            model = newModel;
        }
        Map<String, List<Object[]>> collect =
                model.stream().collect(Collectors.groupingBy(objects -> (String) objects[0]));  // 将数据库数据根据bigType分组
        charts.getOption().setSeries(setSeriesContent(charts, collect));
        charts.getOption().setRadar(setRadarContent(charts, collect));
        charts.getOption().getLegend().setData(new ArrayList<>(collect.keySet()));
    }

    /**
     * 设置Series内容
     *
     * @param charts
     * @param collect
     * @return
     */
    private Object setSeriesContent(ECharts charts, Map<String, List<Object[]>> collect) {
        if (charts.getOption().getSeries() instanceof Map) {  // Series是键值对的形式
            Map<String, Object> series = (Map<String, Object>) charts.getOption().getSeries();
            return setSeriesData(series, collect);
        } else if (charts.getOption().getSeries() instanceof List) {  // Series是列表里嵌套键值对的形式
            List<Map<String, Object>> seriesList = (List) charts.getOption().getSeries();
            if (seriesList.size() == 1) {  // Series列表里只有一条数据
                // 设置这一条的数据
                seriesList.set(0, setSeriesData(seriesList.get(0), collect));
                return seriesList;
            } else {  // Series列表里有多条数据
                // 暂待实现
                return charts.getOption().getSeries();
            }
        }
        return charts.getOption().getSeries();  // 设置失败，返回模板
    }

    /**
     * 设置Series里data
     *
     * @param series  单个series
     * @param collect 分组后的数据库数据
     * @return 设置了数据的series
     */
    private Map<String, Object> setSeriesData(Map<String, Object> series, Map<String, List<Object[]>> collect) {
        List<Map<String, Object>> dataList = new ArrayList<>();  // data列表
        for (String bigType : collect.keySet()) {
            Map<String, Object> dataMap = new HashMap<>();  // data列表下单个map
            List<Object> valueList = new ArrayList<>();  // 分组后的实际值
            for (Object[] object : collect.get(bigType)) {
                valueList.add(object[2]);
            }
            dataMap.put("value", valueList);
            dataMap.put("name", bigType);
            dataList.add(dataMap);
        }
        series.put("data", dataList);
        return series;
    }

    /**
     * 设置radar的内容
     *
     * @param charts
     * @param collect
     * @return
     */
    private Object setRadarContent(ECharts charts, Map<String, List<Object[]>> collect) {
        if (charts.getOption().getRadar() instanceof Map) {  // radar是键值对的形式
            Map<String, Object> radar = (Map<String, Object>) charts.getOption().getRadar();
            return setRadarIndicator(radar, collect);
        } else if (charts.getOption().getRadar() instanceof List) { // radar是列表里嵌套键值对的形式
            List<Map<String, Object>> radarList = (List<Map<String, Object>>) charts.getOption().getRadar();
            if (radarList.size() == 1) { // radar列表里只有一条数据
                // 设置这一条的数据
                radarList.set(0, setRadarIndicator(radarList.get(0), collect));
                return radarList;
            } else {  // Series列表里有多条数据
                // 暂待实现
                return charts.getOption().getRadar();
            }
        }
        return charts.getOption().getRadar();  // 设置失败，返回模板
    }

    /**
     * 设置radar的indicator
     *
     * @param radar   单个radar
     * @param collect 分组后的数据库数据
     * @return 设置了indicator的radar
     */
    private Map<String, Object> setRadarIndicator(Map<String, Object> radar, Map<String, List<Object[]>> collect) {
        List<Object> indicatorList = new ArrayList<>();  // indicator列表
        for (String bigType : collect.keySet()) {
            for (Object[] objects : collect.get(bigType)) {
                Map<String, Object> indicatorMap = new HashMap<>();  // indicator下单个map
                indicatorMap.put("name", objects[1]);
                if (objects.length == 4) {
                    indicatorMap.put("max", objects[3]);
                }
                indicatorList.add(indicatorMap);
            }
            break;
        }
        radar.put("indicator", indicatorList);
        return radar;
    }
}
